/*
 *chat_client
 */
#include "chat_message.h"
#include <boost/asio.hpp>
#include <deque>
#include <iostream>
#include <thread>
#include <cstdlib>

using boost::asio::ip::tcp;

using chat_message_queue = std::deque<chat_message>;
//deque从头尾插入删除均方便，且迭代器不会失效
class chat_client {
public:
	chat_client(boost::asio::io_service &io_service,
							tcp::resolver::iterator endpoint_iterator)
				: io_service_(io_service), socket_(io_service) {
			do_connect(endpoint_iterator);
		}
	void write(const chat_message &msg) {
		io_service_.post([this, msg]() {
			bool write_in_progress = !write_msgs_.empty();
			write_msgs_.push_back(msg);
			if(!write_in_progress) {
				do_write();
			}
		});//生成一个事件，在io_service控制下跑
	}

	void close() {
		io_service_.post([this]() { socket_.close(); });
	}

private:
	//连接作为异步，把事件注册进去，客户端加载资源，连接慢慢来，连接好了调用回调
	void do_connect(tcp::resolver::iterator endpoint_iterator) {
		boost::asio::async_connect(
				socket_, endpoint_iterator,
				[this](boost::system::error_code ec, tcp::resolver::iterator) {
					if(!ec) {
						do_read_header();
					}
				});
	}

	void do_read_header() {
		boost::asio::async_read(
				socket_, boost::asio::buffer(read_msg_.data(), chat_message::header_length),
				[this](boost::system::error_code ec, std::size_t /*length*/) {
					if(!ec && read_msg_.decode_header()) {
						do_read_body();
					} else {
						socket_.close(); //客户端主动关闭链接
					}
				});
	}
	void do_read_body() {
		boost::asio::async_read(
				socket_, boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
				[this](boost::system::error_code ec, std::size_t /*length*/) {
					if(!ec) {
						std::cout.write(read_msg_.body(), read_msg_.body_length());
						std::cout << "\n";
						do_read_header();
					} else {
						socket_.close();
					}
				});
	}
	void do_write() {
		boost::asio::async_write(
				socket_, boost::asio::buffer(write_msgs_.front().data(),
																		 write_msgs_.front().length()),
				[this](boost::system::error_code ec, std::size_t /*length*/) {
					if(!ec){
						write_msgs_.pop_front();
						if (!write_msgs_.empty()) {
							do_write();
						}
					} else {
					socket_.close();
					}
				});
	}


	boost::asio::io_service &io_service_;
	tcp::socket socket_;
	chat_message read_msg_;
	chat_message_queue write_msgs_;
};

int main(int argc, char *argv[]) {
	try {
		if(argc != 3) {
			std::cerr << "Usage: chat_client <host><port>\n";
			return 1;
		}
		boost::asio::io_service io_service;
		//分析host port
		tcp::resolver resolver(io_service);
		auto endpoint_iterator = resolver.resolve({argv[1], argv[2]});
		chat_client c(io_service, endpoint_iterator);
	  //构造，异步连接服务器	
		std::thread t([&io_service]() {io_service.run();});

		char line[chat_message::max_body_length + 1];
		//ctrl-d
		//ctrl-c interrupt
		while (std::cin.getline(line, chat_message::max_body_length + 1)) {
			chat_message msg;
			msg.body_length(std::strlen(line));//<=512
			std::memcpy(msg.body(), line, msg.body_length());
			msg.encode_header();
			c.write(msg);
		}

		c.close();
		t.join();
	} catch (std::exception &e) {
		std::cerr << "Exception: " << e.what() << "\n";
	}
	
	return 0;
}
